import { AFFIX_REGEXP, AFFIX_TEMPLATE } from "../../frame/frame.config";
import { http_send } from "../../frame/network/HttpService";
import { DEFAULT_BODY, ServiceAPIStructureMap, ServiceAPIURI, ServiceBody, ServiceRequest, ServiceResponse } from "./config.api.service";

const ServerURL = "http://am.33t8y678tyy6rt.top/";

export default class ServiceAPI {
	private static used_token: string[] = [];
	private static async send <uri extends ServiceAPIURI> ( api: uri, data?: ServiceAPIStructureMap[uri]['request']['data'] ){
		let url = ServerURL+api;
		let request: ServiceRequest<uri> = {data} as any;
		request.ccToken = mtec.string.randomToken(5, 36, t=>!ServiceAPI.used_token.includes(t));
		request.data = data;
		Object.assign(request, DEFAULT_BODY);
		formatRequest(request);
		let response: ServiceResponse<uri> = await http_send(url, request, 'POST');
		parseResponse(response);

		return response;
	}

	public static async userInit(
		deviceId: ServiceBody<ServiceAPIURI.InitUser>['deviceId'],
		country: ServiceBody<ServiceAPIURI.InitUser>['country'],
	){
		let response = await ServiceAPI.send(ServiceAPIURI.InitUser, {deviceId, country});
		return response.success ? response.result : void 0;
	}

	public static async userInfo(
		userId: ServiceBody<ServiceAPIURI.UserInfo>['userId']
	){
		let response = await ServiceAPI.send(ServiceAPIURI.UserInfo, {userId});
		return response.success ? response.result : void 0;
	}

	public static async countConf(
		country: ServiceBody<ServiceAPIURI.ConfCoun>['country']
	){
		let response = await ServiceAPI.send(ServiceAPIURI.ConfCoun, {country});
		return response.success ? response.result : void 0;
	}

	public static async otherConf(
		country: ServiceBody<ServiceAPIURI.ConfOther>['country']
	){
		let response = await ServiceAPI.send(ServiceAPIURI.ConfOther, {country});
		return response.success ? response.result : void 0;
	}

	public static async fruitGet(
		userId: ServiceBody<ServiceAPIURI.FruitGet>['userId'],
		type: ServiceBody<ServiceAPIURI.FruitGet>['type'],
		level: ServiceBody<ServiceAPIURI.FruitGet>['level'],
	){
		let response = await ServiceAPI.send(ServiceAPIURI.FruitGet, {userId, type, level});
		return response.success ? response.result : void 0;
	}

	public static async fruitConfirm(
		userId: ServiceBody<ServiceAPIURI.FruitConfirm>['userId'],
		logId: ServiceBody<ServiceAPIURI.FruitConfirm>['logId'],
		type: ServiceBody<ServiceAPIURI.FruitConfirm>['type']
	){
		let response = await ServiceAPI.send(ServiceAPIURI.FruitConfirm, {userId, logId, type});
		return response.success ? response.result : void 0;
	}

	public static async symbolClean(
		userId: ServiceBody<ServiceAPIURI.SymbolClean>['userId'],
		cache: ServiceBody<ServiceAPIURI.SymbolClean>['cache'],
		round?: ServiceBody<ServiceAPIURI.SymbolClean>['round']
	){
		let response = await ServiceAPI.send(ServiceAPIURI.SymbolClean, {userId, cache, round});
		return response.success ? response.result : void 0;
	}

	public static async diamondSync(
		userId: ServiceBody<ServiceAPIURI.DiamondSync>['userId'],
		diamond: ServiceBody<ServiceAPIURI.DiamondSync>['diamond']
	){
		let response = await ServiceAPI.send(ServiceAPIURI.DiamondSync, {userId, diamond});
		return response.success ? response.result : void 0;
	}

	public static async Free(
		userId: ServiceBody<ServiceAPIURI.Free>['userId'],
		freeID: ServiceBody<ServiceAPIURI.Free>['freeID'],
		account: ServiceBody<ServiceAPIURI.Free>['account'],
		accountType: ServiceBody<ServiceAPIURI.Free>['accountType'],
		accountName: ServiceBody<ServiceAPIURI.Free>['accountName'],
		channel: ServiceBody<ServiceAPIURI.Free>['channel'],
	){
		let response = await ServiceAPI.send(ServiceAPIURI.Free, {userId, freeID, account, accountType, accountName, channel});
		return response.success ? response.result : void 0;
	}

	public static async GCreate(
		userId: ServiceBody<ServiceAPIURI.GCreate>['userId'],
		goodsId: ServiceBody<ServiceAPIURI.GCreate>['goodsId'],
	){
		let response = await ServiceAPI.send(ServiceAPIURI.GCreate, {userId, goodsId});
		return response.success ? response.result : void 0;
	}

	public static async GStatus(
		userId: ServiceBody<ServiceAPIURI.GStatus>['userId'],
		GMFID: ServiceBody<ServiceAPIURI.GStatus>['GMFID']
	){
		let response = await ServiceAPI.send(ServiceAPIURI.GStatus, {userId, GMFID});
		return response.success ? response.result : void 0;
	}

	public static async Unlock(userId: ServiceBody<ServiceAPIURI.Unlock>['userId']){
		let response = await ServiceAPI.send(ServiceAPIURI.Unlock, {userId});
		return response.success ? response.result.unlock : false;
	}
}

function formatRequest(request: any){
	let list = [];

	if(typeof request == 'object' && !Array.isArray(request)){
		list.unshift(request);
	}

	while(list.length>0){
		let item = list.pop();
		if(Array.isArray(item)){
			item.forEach(el=>{
				if(typeof el == 'object'){
					list.unshift(el);
				}
			});
		}else{
			for(let [key, value] of Object.entries(item)){
				if(typeof value == 'object'){
					list.unshift(value);
				}

				Reflect.set(item, AFFIX_TEMPLATE.service.replace('key', key), value);
				Reflect.deleteProperty(item, key);
			}
		}
	}

	return request;
}

function parseResponse(response: any){
	let list = [];

	if(typeof response == 'object' && !Array.isArray(response)){
		list.unshift(response);
	}

	while(list.length>0){
		let item = list.pop();
		if(Array.isArray(item)){
			item.forEach(el=>{
				if(typeof el == 'object'){
					list.unshift(el);
				}
			});
		}else if(item){
			for(let [key, value] of Object.entries(item)){
				if(typeof value == 'object'){
					list.unshift(value);
				}

				Reflect.set(item, key.replace(AFFIX_REGEXP.service, '$1'), value);
				Reflect.deleteProperty(item, key);
			}
		}
	}

	return response;
}